/*
 * AutoReferee.h
 *
 *  Created on: 2011-03-20
 *      Author: kamil
 */

#ifndef AUTOREFEREE_H_
#define AUTOREFEREE_H_

#include "mgr/video/Videoclient.h"
#include "mgr/id/ModelId.h"
#include "mgr/util/types.h"
#include "mgr/util/Position2d.h"
#include "CmdLineParser.h"
#include "Server.h"
#include "Analyzer.h"
#include "GazeboClient.h"
#include "common.h"
#include <map>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <log4cxx/logger.h>

class AutoReferee {
private:
	/**
	 * Determines the referee state and possible commands to be send
	 */
	enum RefereeState { S_PRE_FIRST_HALF, S_GOAL, S_KICKOFF, S_READY, S_STOP, S_BALL_PLACEMENT};

	struct PlacementInfo {
		bool goal;
		Vector2d pos;
		GameInfo lastGameInfo;
		boost::posix_time::ptime startTime;
	};

	struct BallOutDecision {
		Vector2d ballPos;
		char cmd;
	};


public:
	AutoReferee(boost::asio::io_service & io_service, const CmdLineParser & config);
	~AutoReferee();

	void run();

private:
	/**
	 * If enough time passed, sends the current packet - it should be well prepared
	 */
	void multicast();
	void send();
	void updateState();
	void createCommand(char newCommand);

	Position2d getPosition(ModelId);

	/**
	 * Calculates decision after ball out (out/kickoff/goal) and ball
	 * placement position
	 */
	BallOutDecision calculateBallOutDecision();
	/**
	 * Checks which goal belongs to which team.
	 */
	void calculateGoalOwners();
	/**
	 * Returns closest robot id to the given point. Skips the ball
	 */
	ModelId getClosestRobot(Vector2d point);
	/**
	 * Checks if robots are properly placed before kickoff (especially after goal)
	 */
	bool validateRobotPositions();

private:
	boost::asio::io_service & io_service;
	Videoclient videoClient;
	Server server;

	GameStatePacket currentCmdPacket;

	RefereeState state;

	Analyzer videoAnalyzer;

	GazeboClient gazeboClient;

	GameInfo gameInfo;

	static const int PLACEMENT_DELAY = 5000;

	boost::posix_time::ptime lastMulticastTime;

	std::map<ModelId, Videodata> modelsData;

	static const int MULTICAST_PERIOD = 1000; //ms

	PlacementInfo placementInfo;

	boost::posix_time::ptime placementStart;

	BallOutDecision ballOutDecision;

	TeamName firstGoalOwners;
	TeamName secondGoalOwners;

	bool goalScored;

	static log4cxx::LoggerPtr logger;
};

#endif /* AUTOREFEREE_H_ */
